export interface DisposeCallbackParam<T extends object = {}> {
  searchParams: URLSearchParams
  response: T
}

export type DisposeCallback<T extends object = {}> = (param: DisposeCallbackParam<T>) => void

export interface DisposeOption<T extends object> {
  hostname: string
  pathname: string
  /** 被注册的接口数据处理函数 */
  processor: DisposeCallback<T>
  /** 注册之后需要干的事情 */
  then?: () => void
}

const disposeTool: Map<string, Set<DisposeCallback<any>>> = window.disposeTool ?? (window.disposeTool = new Map())

export function registerDispose<T extends object>(option: DisposeOption<T>) {
  const { hostname, pathname, processor, then } = option

  const origin = hostname + pathname
  let tool = disposeTool.get(origin)
  if (!tool) disposeTool.set(origin, (tool = new Set()))
  tool.add(processor)
  then?.()
}

export function executeDispose(urlText: string, response: string) {
  const { hostname, pathname, searchParams } = new URL(urlText)
  const origin = hostname + pathname
  const tool = disposeTool.get(origin)

  if (tool) {
    try {
      const data = { searchParams, response: JSON.parse(response) }
      tool.forEach((fn) => fn(data))
    } catch (error) {
      if (import.meta.env.DEV) {
        throw error
      }
    }
  }
}

const Injected = '--is-injected--0x--'

export function initializeXMLHttpRequest() {
  // @ts-ignore
  if (XMLHttpRequest[Injected]) return

  Reflect.defineProperty(XMLHttpRequest, Injected, {
    value: true,
    configurable: false,
    enumerable: false,
  })

  const send = XMLHttpRequest.prototype.send

  XMLHttpRequest.prototype.send = function (body?: Document | XMLHttpRequestBodyInit | null) {
    this.addEventListener('loadend', ({ target }) => {
      if (!target) return

      const { status, response, responseURL } = target as XMLHttpRequest
      if (status !== 200 || !responseURL || !response) return

      executeDispose(responseURL, response)
    })

    return send.call(this, body)
  }
}